package com.nuoniu.sibanyun.service.expenses.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.entity.expenses.ExpensesBusinessOrder;
import com.nuoniu.sibanyun.entity.expenses.ExpensesProperty;
import com.nuoniu.sibanyun.entity.expenses.dto.ChangeRenewalTypeDto;
import com.nuoniu.sibanyun.entity.expenses.dto.ExpensesPropertySearchDto;
import com.nuoniu.sibanyun.entity.expenses.dto.RenewalDto;
import com.nuoniu.sibanyun.mapper.expenses.ExpensesPropertyMapper;
import com.nuoniu.sibanyun.service.crm.call.ICrmCallAgentService;
import com.nuoniu.sibanyun.service.expenses.IExpensesAccountService;
import com.nuoniu.sibanyun.service.expenses.IExpensesBusinessOrderService;
import com.nuoniu.sibanyun.service.expenses.IExpensesPropertyService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 费用中心-续费管理 服务实现类
 * </p>
 *
 * @author 白强
 * @since 2022-05-09
 */
@Service
@Log4j2
public class ExpensesPropertyServiceImpl extends ServiceImpl<ExpensesPropertyMapper, ExpensesProperty> implements IExpensesPropertyService {

    @Autowired
    private IExpensesAccountService accountService;
    @Autowired
    private IExpensesBusinessOrderService businessOrderService;
    @Autowired
    private ICrmCallAgentService agentService;

    @Override
    public void addExpensesProperty(ExpensesProperty expensesProperty) {
        String firstStr = "";
        String productionType = expensesProperty.getProductionType();
        UserInfo userInfo = UserThreadLocal.get();
        ExpensesProperty oldExpensesProperty = this.checkExpensesProperty(expensesProperty);
        if(null != oldExpensesProperty){
            Integer status = oldExpensesProperty.getStatus();
            if(0 == status)throw new NuoNiuException("产品已购买,暂未生效");
            if(1 == status)throw new NuoNiuException("产品已经生效中，无需再购买");
            if(2 == status)throw new NuoNiuException("产品未续费，请前往付费");
        }
        switch (productionType){
            case "baseProduction": firstStr = "BASE_";break;
            case "callSetting": firstStr = "CS_";break;
            case "callAgent": firstStr = "CA_";break;
        }
        String randomStr = StringUtils.getUUID(15, 1);
        String uuid = firstStr + randomStr;

        expensesProperty.setCompanyId(userInfo.getCompanyId());
        expensesProperty.setPropertyUuid(uuid);
        expensesProperty.setPropertyName(expensesProperty.getProductionName()+StringUtils.getRandomStr(4));
        save(expensesProperty);
    }

    @Override
    public ExpensesProperty checkExpensesProperty(ExpensesProperty expensesProperty) {
        String productionType = expensesProperty.getProductionType();
        if("callAgent".equals(productionType)){
            return null;
        }
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<ExpensesProperty> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.eq("production_type",productionType);
        queryWrapper.ne("status",400);
        queryWrapper.last("LIMIT 1");
        return getOne(queryWrapper,false);
    }

    @Override
    public ExpensesProperty getByUUid(String propertyUuid) {
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<ExpensesProperty> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.eq("property_uuid",propertyUuid);
        queryWrapper.last("LIMIT 1");
        return getOne(queryWrapper,false);
    }

    @Override
    public Page<ExpensesProperty> pageList(ExpensesPropertySearchDto propertySearchDto) {
        UserInfo userInfo = UserThreadLocal.get();
        String productionName = propertySearchDto.getProductionName();
        String productionType = propertySearchDto.getProductionType();
        Integer renewalType = propertySearchDto.getRenewalType();
        String startTime = propertySearchDto.getStartTime();
        String endTime = propertySearchDto.getEndTime();

        QueryWrapper<ExpensesProperty> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        if(StringUtils.isNotBlank(productionName)){
            queryWrapper.like("production_name",productionName);
        }
        if(StringUtils.isNotBlank(productionType)){
            queryWrapper.eq("production_type",productionType);
        }
        if(StringUtils.isNotBlank(startTime)){
            queryWrapper.ge("end_time",startTime).or().ge("auto_renewal_time",startTime);
        }
        if(StringUtils.isNotBlank(endTime)){
            queryWrapper.lt("end_time",endTime).or().lt("auto_renewal_time",endTime);
        }
        if(null != renewalType){
            queryWrapper.eq("renewal_type",renewalType);
        }
        Page page = page(propertySearchDto.getPage(), queryWrapper);
        return page;
    }

    @Override
    public void changeRenewalType(ChangeRenewalTypeDto changeRenewalTypeDto) {

        Long id = changeRenewalTypeDto.getId();
        Integer renewalType = changeRenewalTypeDto.getRenewalType();
//        Integer autoRenewalPeriod = changeRenewalTypeDto.getAutoRenewalPeriod();
//        BigDecimal autoRenewalAmount = changeRenewalTypeDto.getAutoRenewalAmount();
        UserInfo userInfo = UserThreadLocal.get();
        Integer companyId = userInfo.getCompanyId();
        if(null == id || null == renewalType || (!renewalType.equals(1) && !renewalType.equals(2)))throw new NuoNiuException("参数错误");
        ExpensesProperty expensesProperty = this.getById(id);
        if(null == expensesProperty)throw new NuoNiuException("参数错误");
        if(!companyId.equals(expensesProperty.getCompanyId()))throw new NuoNiuException("订单错误");
        Integer status = expensesProperty.getStatus();
        if(status.equals(400))throw new NuoNiuException("订单状态错误");
//        if(renewalType.equals(2) && (null == autoRenewalPeriod || null == autoRenewalAmount))throw new NuoNiuException("自动续费参数错误");
        UpdateWrapper<ExpensesProperty> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",id);
        updateWrapper.set("renewal_type",renewalType);
//        if (renewalType.equals(2)) {
//            updateWrapper.set("auto_renewal_period",autoRenewalPeriod);
//            updateWrapper.set("auto_renewal_amount",autoRenewalAmount);
//        }
        update(updateWrapper);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRenewal(List<RenewalDto> renewalDtos, List<ExpensesProperty> propertyList)     {
        LocalDateTime now = LocalDateTime.now();
        Map<Long,ExpensesProperty> propertyMap = new HashMap<>();
        propertyList.forEach(f->propertyMap.put(f.getId(),f));
        /** 1.1 .需要更新的资源 */
        List<ExpensesProperty> updateExpensesProperties = new ArrayList<>();
        /** 1.2 .新增续费订单 */
        List<ExpensesBusinessOrder> businessOrderList = new ArrayList<>();
        Map<String,ExpensesBusinessOrder> businessOrderMap = new HashMap<>();
        renewalDtos.forEach(renewalDto -> {
            Integer renewalNumber = renewalDto.getRenewalNumber();
            ExpensesProperty expensesProperty = propertyMap.get(renewalDto.getId());
            if(null == expensesProperty)return;
            Long propertyId = expensesProperty.getId();
            String propertyUuid = expensesProperty.getPropertyUuid();
            String renewalUnit = expensesProperty.getRenewalUnit();
            LocalDateTime endTime = expensesProperty.getEndTime();
            if(now.compareTo(endTime) > 0){
                endTime = now;
            }
            switch (renewalUnit){
                case "年": endTime = endTime.plusYears(renewalNumber.longValue());break;
                case "月": endTime = endTime.plusMonths(renewalNumber.longValue());break;
                case "日": endTime = endTime.plusDays(renewalNumber.longValue());break;
            }
            ExpensesProperty updateExpensesProperty = new ExpensesProperty();
            updateExpensesProperty.setId(propertyId);
            updateExpensesProperty.setStatus(1);
            updateExpensesProperty.setEndTime(endTime);
            updateExpensesProperty.setBusinessIds(expensesProperty.getBusinessIds());
            updateExpensesProperty.setPropertyUuid(expensesProperty.getPropertyUuid());
//            updateExpensesProperty.setAutoRenewalTime(endTime);
            updateExpensesProperties.add(updateExpensesProperty);
            //查询 上次订单详情
            Long lastBusinessOrderId = expensesProperty.getLastBusinessOrderId();
            if(null == lastBusinessOrderId)throw new NuoNiuException("资源信息错误");
            ExpensesBusinessOrder lastBusinessOrder = businessOrderService.getById(lastBusinessOrderId);
            if(null == lastBusinessOrder)throw new NuoNiuException("资源信息错误");
            /** 计算续费订单金额 */
            BigDecimal amount = lastBusinessOrder.getPrice().multiply(new BigDecimal(renewalNumber)).setScale(2, BigDecimal.ROUND_HALF_UP);
            /** 生成续费订单号 */
            String businessIdsStr = expensesProperty.getBusinessIds();
            List<Long> businessIds = JSON.parseArray(businessIdsStr, Long.class);
            String businessOrderNo = lastBusinessOrder.getBusinessOrderNo();
            String[] businessOrderNoArr = businessOrderNo.split("_");
            businessOrderNo = businessOrderNoArr[businessOrderNoArr.length - 1] + "_" + businessIds.size();
            ExpensesBusinessOrder renewalOrder = new ExpensesBusinessOrder();
            BeanUtils.copyProperties(lastBusinessOrder,renewalOrder);
            renewalOrder.setId(null);
            renewalOrder.setOrderType(2);   //续费
//            renewalOrder.setSourcePropertyUuid(propertyUuid);
            renewalOrder.setTimeNumber(renewalNumber);
            renewalOrder.setStatus(3);   //交易完成
            renewalOrder.setOrderAmount(amount);
            renewalOrder.setBusinessOrderNo(businessOrderNo);
            businessOrderList.add(renewalOrder);
            businessOrderMap.put(propertyUuid,renewalOrder);
        });
        /** 2.生成业务订单 */
        if(businessOrderList.size() > 0){
            /** 2.1 .扣费 */
            businessOrderList.forEach(businessOrder -> accountService.changeFromBusinessOrder(businessOrder));
            /** 2.2 .保存订单 */
            businessOrderService.saveBatch(businessOrderList);
        }
        /** 4.批量保存 */
        if(updateExpensesProperties.size() > 0){
            updateExpensesProperties.forEach(expensesProperty -> {
                ExpensesBusinessOrder businessOrder = businessOrderMap.get(expensesProperty.getPropertyUuid());
                Long orderId = businessOrder.getId();
                String businessIdsStr = expensesProperty.getBusinessIds();
                List<Long> businessIds = JSON.parseArray(businessIdsStr, Long.class);
                businessIds.add(orderId);
                expensesProperty.setLastBusinessOrderId(orderId);
                expensesProperty.setBusinessIds(JSON.toJSONString(businessIds));
            });
            this.updateBatchById(updateExpensesProperties);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRenewalByCompany(List<RenewalDto> renewalDtos) {
        Set<Long> ids = renewalDtos.stream().map(RenewalDto::getId).collect(Collectors.toSet());
        UserInfo userInfo = UserThreadLocal.get();
        /** 1.查询批量续费的资源集合 */
        QueryWrapper<ExpensesProperty> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.in("id",ids);
        List<ExpensesProperty> propertyList = list(queryWrapper);
        this.batchRenewal(renewalDtos,propertyList);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void autoRenewal() {
        /** 1.查询 今日自动续费的资源 */
        List<ExpensesProperty> propertyList = baseMapper.listAutoRenewalProperty();
        List<ExpensesProperty> failedPropertyList = new ArrayList<>();
        /** 2.自动续费 */
        int size = propertyList.size();
        for (int i = 0; i < size; i++) {
            List<ExpensesProperty> updatePropertyList = new ArrayList<>();
            ExpensesProperty expensesProperty = propertyList.get(i);
            updatePropertyList.add(expensesProperty);
            List<RenewalDto> renewalDtos = new ArrayList<>();
            RenewalDto renewalDto = new RenewalDto();
            renewalDtos.add(renewalDto);
            renewalDto.setId(expensesProperty.getId());
            renewalDto.setRenewalNumber(expensesProperty.getAutoRenewalPeriod());
            try {
                this.batchRenewal(renewalDtos,updatePropertyList);
            }catch (Exception e){
                log.info("资源ID:{},自动续费失败，原因：{}",expensesProperty.getPropertyUuid(),e.getMessage());
                failedPropertyList.add(expensesProperty);
            }
        }

        if(failedPropertyList.size() > 0){
            log.info("自动续费失败的资源{}个,开始执行关闭任务...",failedPropertyList.size());
            this.batchCloseService(failedPropertyList);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void checkDeadline() {
        List<ExpensesProperty> propertyList = baseMapper.listDeadlineProperty();
        if(propertyList.size() > 0){
            log.info("查询到过期资源{}个,开始执行关闭任务...",propertyList.size());
            this.batchCloseService(propertyList);
        }
    }

    /**
     * 批量关闭 资源关联服务
     * @param closeExpensesPropertyList
     * @return
     */
    @Override
    public void batchCloseService(List<ExpensesProperty> closeExpensesPropertyList) {
        int size = closeExpensesPropertyList.size();
        //todo  更多产品关联业务 请在这里添加
        List<ExpensesProperty> agentList = new ArrayList<>();
        for (int i = 0; i <size ; i++) {
            ExpensesProperty expensesProperty = closeExpensesPropertyList.get(i);
            String productionType = expensesProperty.getProductionType();
            switch (productionType){
                case "callAgent": agentList.add(expensesProperty);break;
            }
        }
        if(agentList.size() > 0){
            agentService.batchUpdateAgentFromExpensesProperty(agentList,2);
        }
    }

    /**
     * 批量开启 资源关联服务
     * @param openExpensesPropertyList
     * @return
     */
    @Override
    public void batchOpenService(List<ExpensesProperty> openExpensesPropertyList) {
        int size = openExpensesPropertyList.size();
        //todo  更多产品关联业务 请在这里添加
        List<ExpensesProperty> agentList = new ArrayList<>();
        for (int i = 0; i <size ; i++) {
            ExpensesProperty expensesProperty = openExpensesPropertyList.get(i);
            String productionType = expensesProperty.getProductionType();
            switch (productionType){
                case "callAgent": agentList.add(expensesProperty);break;
            }
        }
        if(agentList.size() > 0){
            agentService.batchUpdateAgentFromExpensesProperty(agentList,1);
        }
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void changeFromBusinessOrder(ExpensesBusinessOrder businessOrder) {
        Integer orderStatus = businessOrder.getStatus();
        //状态 0.待支付 1.处理中 2.已取消 3.交易成功 4.已过期
        if(!orderStatus.equals(3))throw new NuoNiuException("订单未交易完成");
        LocalDateTime createTime = businessOrder.getCreateTime();
        String timeUnit = businessOrder.getTimeUnit();
        Integer timeNumber = businessOrder.getTimeNumber();
        Integer renewalType = businessOrder.getRenewalType();
        Integer orderType = businessOrder.getOrderType();
        String productionType = businessOrder.getProductionType();
        if(null == timeNumber)throw new NuoNiuException("请选择产品时限");
        /**1.新购 */
        if( orderType.equals(1)){
            ExpensesProperty expensesProperty = new ExpensesProperty();
            expensesProperty.setLastBusinessOrderId(businessOrder.getId());
            List<Long> businessIds = new ArrayList<>();
            businessIds.add(businessOrder.getId());
            expensesProperty.setBusinessIds(JSON.toJSONString(businessIds));
            expensesProperty.setRenewalType(renewalType);
            LocalDateTime endTime = createTime;
            switch (timeUnit){
                case "年": endTime = createTime.plusYears(timeNumber.longValue());break;
                case "月": endTime = createTime.plusMonths(timeNumber.longValue());break;
                case "日": endTime = createTime.plusDays(timeNumber.longValue());break;
            }
            expensesProperty.setRenewalUnit(timeUnit);
            expensesProperty.setEndTime(endTime);
//            expensesProperty.setAutoRenewalTime(endTime);
            switch (productionType){
                case "callAgent":
                    expensesProperty.setMinimumRenewalPeriodPrice(businessOrder.getPrice());
                    break;
                case "callSetting":
                    expensesProperty.setMinimumRenewalPeriodPrice(BigDecimal.ZERO);
                    break;
            }
            expensesProperty.setMinimumRenewalPeriod(1);
            expensesProperty.setStatus(1);
            expensesProperty.setProductionId(businessOrder.getProductionId());
            expensesProperty.setProductionName(businessOrder.getProductionName());
            expensesProperty.setProductionSpecifications(businessOrder.getProductionSpecifications());
            expensesProperty.setProductionType(productionType);
            this.addExpensesProperty(expensesProperty);
            /** 更新 业务订单的 来源资源ID(资源唯一标识)*/
            ExpensesBusinessOrder updateExpensesBusinessOrder = new ExpensesBusinessOrder();
//            updateExpensesBusinessOrder.setSourcePropertyUuid(expensesProperty.getPropertyUuid());
            updateExpensesBusinessOrder.setId(businessOrder.getId());
            businessOrderService.updateById(updateExpensesBusinessOrder);
        }
        /** 2.续费*/
        else if(orderType.equals(2)){
//            String sourcePropertyUuid = businessOrder.getSourcePropertyUuid();
//            ExpensesProperty oldExpensesProperty = this.getByUUid(sourcePropertyUuid);
//            if(null == oldExpensesProperty)throw new NuoNiuException("续费失败，请重新购买");
//            LocalDateTime endTime = oldExpensesProperty.getEndTime();
//            switch (timeUnit){
//                case "年": endTime = endTime.plusYears(timeNumber.longValue());break;
//                case "月": endTime = endTime.plusMonths(timeNumber.longValue());break;
//                case "日": endTime = endTime.plusDays(timeNumber.longValue());break;
//            }
//            ExpensesProperty expensesProperty = new ExpensesProperty();
//            expensesProperty.setId(oldExpensesProperty.getId());
//            expensesProperty.setEndTime(endTime);
//            this.updateById(expensesProperty);
        }
        /** 3.变更*/
        else if(orderType.equals(3)){
//            String sourcePropertyUuid = businessOrder.getSourcePropertyUuid();
//            ExpensesProperty oldExpensesProperty = this.getByUUid(sourcePropertyUuid);
//            if(null == oldExpensesProperty)throw new NuoNiuException("变更失败，请重新购买");
//            ExpensesProperty updateOldExpensesProperty = new ExpensesProperty();
//            updateOldExpensesProperty.setId(oldExpensesProperty.getId());
//            updateOldExpensesProperty.setStatus(400);
//            this.updateById(updateOldExpensesProperty);
//            businessOrder.setOrderType(1);
//            businessOrder.setSourcePropertyUuid("");
//            this.changeFromBusinessOrder(businessOrder);
        }

    }




}
